package main
import (
	"fmt"
	"errors"
	"os"
)

type AppErr struct{
	code int
	msg  string
	err  error
}

// 内制的error接口非常简单，只有这一个方法，实现它就可以作为error类型使用 
func (e *AppErr) Error() string {
	return fmt.Sprintf("[code %d] %s :%v",e.code,e.msg,e.err)
}

func (e *AppErr) Unwrap() error{
	return e.err
}

func NewAppErr(code int,msg string,err error) *AppErr{
	return &AppErr{
		code:code,
		msg:msg,
		err:err,
	}
}

// apply custom error
func loadConfig(file string) error{
	data,err := os.ReadFile(file)
	if err != nil {
		return NewAppErr(1001,"fail to load config",err)
	}
	fmt.Println("data: ",string(data))
	return nil
}


// 最佳实践：错误码也要用常量封装
func main(){
	err := loadConfig("haha.txt")
	if err != nil{
		var appErr *AppErr
		if errors.As(err,&appErr){
			fmt.Printf("Custom error catch: %s\n",appErr.Error())
		}else{
			fmt.Println("unknow error: ",err)
		}
	}
}